import Mota from "@/mota";
import { ImageName } from "@/mota/data/ImageLoader";
import { DrawSize, MapFloor, UnitInfo } from "@/mota/data/MapDataUtils";

export interface EventCondition {
	floor: MapFloor;
	size: DrawSize[];
	image: ImageName[];
}

export type EventConditionOptional = { [name in keyof EventCondition]?: EventCondition[name]; };

export interface EventInfo<T extends string> {
	remarks: T,
	count: number,
	condition?: EventConditionOptional[];
	handle: (Mota: Mota, EventHandle: EventInfo<T>, unit: UnitInfo, floor: MapFloor, x: number, y: number) => Promise<void>;
}

const MAIL = <T extends string>(data: readonly EventInfo<T>[]) => data;

const eventHandList = MAIL([
	{
		remarks: "1_仙子_梦的开始",
		count: 0,
		condition: [{
			floor: 1,
			image: ["仙子"],
		}],
		async handle(Mota, event) {
			const { map, tip, message } = Mota;
			const { count } = event;
			if (count === 0) {
				await message.Show("仙子", "石地板", "哟，稀客啊，你怎么会到这里来？");
				await message.Show("勇士", "石地板", "这里是哪里？我在这附近砍柴突然被一只很大的蝙蝠抓到这里来了！。");
				await message.Show("仙子", "石地板", "这里就是外界传说中的魔塔，这一层之上的楼层都被魔物所占据");
				await message.Show("仙子", "石地板", "几乎所有来到这里的人，除了打败在8层的魔物首领外不可能逃出这里……");
				await message.Show("仙子", "石地板", "对了，还有魔王抓走了你们国的公主，如果救出了她你下半辈子都不用愁了");
				await message.Show("勇士", "石地板", "让我过去吧！我会救出公主逃出去的！");
				await message.Show("仙子", "石地板", "我看你有些战斗能力，这把红钥匙就给你了。祝你能打败魔王，逃出这里");
				await map.UnitShow(6, 3, "红钥匙");
				await map.UnitLeave(5, 2, "青门");
			} else if (count < 5) {
				await message.Show("仙子", "石地板", "我的能力被魔王所封印。。。无法帮你更多了。。祝你好运");
			} else if (count < 100) {
				tip.AddSay("仙子", "我都说我被封印了，滚");
			} else {
				tip.AddSay("仙子", "滚");
			}
		}
	}, {
		remarks: "2_老人_获得怪物图鉴",
		count: 0,
		condition: [{
			floor: 2,
			image: ["老人"],
		}],
		async handle(Mota, event) {
			const { map, tip, message, hero } = Mota;
			const { count } = event;
			await message.Show("老人", "石地板", "勇士，救出公主打败魔王的重任就在你身上了，我也给不了你太多的帮助");
			await message.Show("老人", "石地板", "这本怪物图鉴是我年轻时所收集的怪物数据，就送给你吧");
			hero.pack.AppendProp("怪物图鉴");
		}
	}, {
		remarks: "2_骷髅武士_拿钥匙就锁门",
		count: 0,
		condition: [{
			floor: 2,
			image: ["黄钥匙", "骷髅武士"],
		}],
		async handle(Mota, event, unit) {
			const { map } = Mota;
			const { count } = event;
			const [target] = unit;
			if (count % 2 === 0 && target === "黄钥匙") {
				await map.UnitEnter(7, 3, "青门");
			} else if (count % 2 === 1 && target === "骷髅武士") {
				await map.UnitLeave(7, 3, "青门");
			}
		}
	}, {
		remarks: "2_初级卫兵_铁盾护卫",
		count: 0,
		condition: [{
			floor: 2,
			image: ["初级卫兵"],
		}],
		async handle(Mota, event) {
			const { map } = Mota;
			const { count } = event;
			if (count % 2 === 1) {
				await map.UnitLeave(9, 8, "青门");
			}
		}
	}, {
		remarks: "3_商人_送门的商人",
		count: 0,
		condition: [{
			floor: 3,
			image: ["奸商"],
		}],
		async handle(Mota, event) {
			const { message, hero } = Mota;
			const { count } = event;
			await message.Show("奸商", "石地板", "勇士，谢谢你把我救了出来，为了表达谢意");
			await message.Show("奸商", "石地板", "这十个随意门就给你了！");
			hero.pack.AppendConsumables("随意门", 10);
		}
	}, {
		remarks: "3_小偷_送钥匙的小偷",
		count: 0,
		condition: [{
			floor: 3,
			image: ["小偷"],
		}],
		async handle(Mota, event) {
			const { hero, tip, message } = Mota;
			const { count } = event;
			await message.Show("小偷", "石地板", "嘿！勇士，瞧见第六层的老头没，他是我朋友，谢谢你救了我");
			await message.Show("小偷", "石地板", "我这有三把铁门钥匙，给你吧！");
			const messageStr = hero.Attribute.AddAttribute([["keyIron", 3]]);
			tip.AddIconMessage("铁门钥匙", `得到${messageStr}`);
		}
	}, {
		remarks: "4_初级卫兵_第五层的钥匙",
		count: 0,
		condition: [{
			floor: 4,
			image: ["初级卫兵"],
		}],
		async handle(Mota, event) {
			const { map } = Mota;
			const { count } = event;
			if (count % 3 === 2) {
				await map.UnitLeave(1, 7, "青门");
			}
		}
	}, {
		remarks: "5_红门_无尽的战斗",
		count: 0,
		condition: [{
			floor: 5,
			image: ["红门", "初级法师", "大蝙蝠", "骷髅人", "骷髅武士", "骷髅队长"],
		}],
		async handle(Mota, event, unit) {
			const { map, message } = Mota;
			const { count } = event;
			const [target] = unit;
			if (target === "红门") {
				event.count = 1;
				await map.UnitShow(5, 5, "骷髅队长");
				await message.Show("骷髅队长", "石地板", "很好，你竟然有能力闯到这里，不过我又怎么会让你从我这通过呢？");
				await message.Show("勇士", "石地板", "别废话！我要杀了你！");
				map.UnitEnter(5, 1, "青门");
				map.UnitEnter(5, 9, "青门");
				map.UnitEnter(4, 5, "青门");
				map.UnitEnter(5, 4, "青门");
				map.UnitEnter(5, 6, "青门");
				await map.UnitEnter(6, 5, "青门");
				await message.Show("骷髅队长", "石地板", "噢？要是我手下们不肯呢？哈哈哈哈");
				await message.Show("骷髅队长", "石地板", "让骷髅族来与你战斗简直是侮辱我们");
				await message.Show("骷髅队长", "石地板", "除非解决掉这些初级法师，你才有资格挑战！");
				await map.UnitLeave(4, 8, "青门");
			}
			else if (target === "初级法师" && count === 1 + 9) {
				await message.Show("骷髅队长", "石地板", "看来有两下子，不过初级法师是无法跟骷髅族媲美的！");
				await message.Show("骷髅队长", "石地板", "如果你能解决掉这群大蝙蝠的话，你才能向我们挑战！");
				await map.UnitLeave(6, 8, "青门");
			}
			else if (target === "大蝙蝠" && count === 1 + 9 + 9) {
				await message.Show("骷髅队长", "石地板", "这怎么可能！你不可能永远都那么幸运！");
				await message.Show("勇士", "石地板", "你真是愚蠢至极，投降吧！");
				await message.Show("骷髅队长", "石地板", "不！你将无法战胜骷髅人！");
				map.UnitLeave(8, 6, "青门");
				await map.UnitLeave(8, 4, "青门");
			}
			else if (target === "骷髅人" && count === 1 + 9 + 9 + 9) {
				await message.Show("骷髅队长", "石地板", "啊！不可能！！他们竟然也失败了！。这是你逼我的！");
				await message.Show("骷髅队长", "石地板", "碰上骷髅武士你必死无疑，来这的勇者无一不死于他们的剑下！");
				map.UnitLeave(6, 2, "青门");
				await map.UnitLeave(4, 2, "青门");
			}
			else if (target === "骷髅武士" && count === 1 + 9 + 9 + 9 + 9) {
				await message.Show("骷髅队长", "石地板", "你！！啊啊啊啊啊啊(接近失去理智)");
				await message.Show("勇士", "石地板", "你已经没机会了，你手上的棋子已空，打开门让我上去！饶你不死！");
				await message.Show("骷髅队长", "石地板", "哼！除非我死了！来吧！我会将你碎尸万段！给我族人复仇！！！");
				map.UnitLeave(2, 4, "青门");
				map.UnitLeave(2, 6, "青门");
				map.UnitLeave(5, 6, "青门");
				map.UnitLeave(4, 5, "青门");
				map.UnitLeave(5, 4, "青门");
				await map.UnitLeave(6, 5, "青门");
			}
			else if (target === "骷髅队长") {
				map.UnitLeave(5, 1, "青门");
				await map.UnitLeave(5, 9, "青门");
				await message.Show("骷髅队长", "石地板", "不！！魔王大人会为我报仇的！勇士！你等着！！");
				map.UnitShow(1, 1, "黄钥匙");
				map.UnitShow(3, 1, "黄钥匙");
				map.UnitShow(1, 3, "黄钥匙");
				map.UnitShow(3, 3, "黄钥匙");
				map.UnitShow(2, 2, "蓝钥匙");
				map.UnitShow(7, 1, "红宝石");
				map.UnitShow(9, 1, "红宝石");
				map.UnitShow(8, 2, "红宝石");
				map.UnitShow(7, 3, "红宝石");
				map.UnitShow(9, 3, "红宝石");
				map.UnitShow(1, 7, "蓝宝石");
				map.UnitShow(3, 7, "蓝宝石");
				map.UnitShow(2, 8, "蓝宝石");
				map.UnitShow(1, 9, "蓝宝石");
				map.UnitShow(3, 9, "蓝宝石");
				map.UnitShow(7, 7, "小血瓶");
				map.UnitShow(9, 7, "小血瓶");
				map.UnitShow(7, 9, "小血瓶");
				map.UnitShow(9, 9, "小血瓶");
				await map.UnitShow(8, 8, "大血瓶");
			}
		}
	},
]);

export type HandRemarks = typeof eventHandList[number]["remarks"];

export type EventHandleMap = { [remarks in HandRemarks]: EventInfo<remarks> };

const eventHandleMap = {} as EventHandleMap;

for (const event of eventHandList) {
	(<any>eventHandleMap)[event.remarks] = event;
}

export function EqualsSize(tx: number, ty: number, size: DrawSize): boolean {
	if (size.length === 2) {
		const [x1, y1] = size;
		if (tx === x1 && ty === y1) {
			return true;
		}
	} else {
		const [x1, y1, x2, y2] = size;
		if (tx >= x1 && ty >= y1 && tx <= x2 && ty <= y2) {
			return true;
		}
	}
	return false;
}

export function EqualsEventCondition(condition: EventConditionOptional, floor: number, x: number, y: number, image: ImageName): boolean {
	if (condition.floor !== undefined) {
		if (condition.floor !== floor) {
			return false;
		}
	}
	if (condition.image !== undefined) {
		if (!condition.image.includes(image)) {
			return false;
		}
	}
	const sizeList = condition.size;
	if (sizeList !== undefined) {
		for (const size of sizeList) {
			if (EqualsSize(x, y, size)) {
				return true;
			}
		}
	}
	return true;
}

export function GetUnitEvent(floor: number, x: number, y: number, image: ImageName): undefined | EventInfo<HandRemarks>[] {
	const list: EventInfo<HandRemarks>[] = [];
	for (const event of eventHandList) {
		const { condition: conditionList } = event;
		if (conditionList === undefined) {
			list.push(event);
		} else {
			for (const condition of conditionList) {
				if (EqualsEventCondition(condition, floor, x, y, image)) {
					list.push(event);
					continue;
				}
			}
		}
	}
	if (list.length === 0) {
		return undefined;
	} else {
		return list;
	}
}

export async function TargetEvent(floor: MapFloor, x: number, y: number, unit: UnitInfo, Mota: Mota): Promise<void> {
	const { tip } = Mota;
	const eventList = GetUnitEvent(floor, x, y, unit[0]);
	if (eventList === undefined) {
		tip.AddIconMessage(unit[0], "该单位无事件内容");
		return;
	}
	for (const event of eventList) {
		await event.handle(Mota, event, unit, floor, x, y);
		event.count++;
	}
}
